#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include "GCriticalSection.h"
#include "GError.h"

namespace GThread
{
	// Description: Creates the critical section.
	// Return: Returns true is criticalsection is created, returns false if method fails.
	// Notes: Cannot create critical section if the state is not RELSEASED.
	// -----------------------------------------------------
	bool GCriticalSection::Create(GUInt32 TheSpinCount)
	{
		if (IsCreated())
		{
			return false;
		}

		Section = new CRITICAL_SECTION;

		BOOL Result = InitializeCriticalSectionAndSpinCount((LPCRITICAL_SECTION)Section, TheSpinCount);
		if (Result == NULL)
		{
			GUtil::GError::Error(GUtil::GErrorMessageWin32(GetLastError()));
			return false;
		}

		SpinCount = TheSpinCount;
		return true;
	}

	// Description: Releases the critical section.
	// Return:
	// Notes: If critical section is owned or released, method will return false.
	// -----------------------------------------------------
	void GCriticalSection::Release()
	{
		if (!IsCreated())
		{
			return;
		}

		DeleteCriticalSection((LPCRITICAL_SECTION)Section);
		
		delete Section;
		Section = NULL;
	}

	// Description: Leaves the critical section.
	// Return: Returns true if successfull, false otherwise
	// Notes: If criticalsection is not owned, method will return false;
	// -----------------------------------------------------
	bool GCriticalSection::Leave()
	{
		GUtil::GError::DebugCheck(!IsCreated(), "Critical section is not created.");
	
		LeaveCriticalSection((LPCRITICAL_SECTION)Section);

		return true;
	}

	// Description: Enters the critical section.
	// Return: Returns false if critical section not created.
	// Notes: Entering multiple times does not cause a deadlock
	// Notes: leave() must be called same times as enter() + tryenter()
	// -----------------------------------------------------
	bool GCriticalSection::Enter()
	{
		GUtil::GError::DebugCheck(!IsCreated(), "Critical section is not created.");

		EnterCriticalSection((LPCRITICAL_SECTION)Section);

		return true;
	}

	// Description: Tries to enter critical section. 
	// Return: True if the critical section is acquired, false otherwise
	// Notes: Critical section must be in initialized state
	// Notes: Entering multiple times does not cause a deadlock
	// Notes: leave() must be called same times as enter() + tryenter()
	// -----------------------------------------------------
	bool GCriticalSection::TryEnter()
	{
		GUtil::GError::DebugCheck(!IsCreated(), "Critical section is not created.");

		BOOL Result = TryEnterCriticalSection((LPCRITICAL_SECTION)Section);
		if (Result == 0)
		{
			return false;
		}

		return true;
	}
}